package org.gdstash.db;

import java.sql.Blob;
import java.util.LinkedList;
import java.util.List;
import java.sql.ResultSet;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.Connection;
import java.sql.SQLException;
import org.gdstash.util.GDMsgLogger;
import org.gdstash.util.GDMsgFormatter;
import org.gdstash.file.ARZRecord;
import java.util.concurrent.ConcurrentHashMap;

public class DBInventoryGrid
{
    private static final String TABLE_NAME = "GDC_INVENTORY_GRID";
    private static final int ROW_RECORD_ID = 1;
    private static final int ROW_X_OFFSET = 2;
    private static final int ROW_X_SIZE = 3;
    private static final int ROW_Y_OFFSET = 4;
    private static final int ROW_Y_SIZE = 5;
    private static ConcurrentHashMap<String, DBInventoryGrid> hashBuffer;
    private String recordID;
    private int xOffset;
    private int xSize;
    private int yOffset;
    private int ySize;
    
    public DBInventoryGrid() {
        this.recordID = null;
    }
    
    public DBInventoryGrid(final ARZRecord record) {
        this();
        this.recordID = record.getFileName();
        this.xOffset = record.getXOffset();
        this.xSize = record.getXSize();
        this.yOffset = record.getYOffset();
        this.ySize = record.getYSize();
    }
    
    public int getXOffset() {
        return this.xOffset;
    }
    
    public int getXSize() {
        return this.xSize;
    }
    
    public int getYOffset() {
        return this.yOffset;
    }
    
    public int getYSize() {
        return this.ySize;
    }
    
    public static void clearBuffer() {
        DBInventoryGrid.hashBuffer.clear();
    }
    
    public static void createTable() throws SQLException {
        final String dropTable = "DROP TABLE GDC_INVENTORY_GRID";
        final String createTable = "CREATE TABLE GDC_INVENTORY_GRID (RECORD_ID        VARCHAR(256) NOT NULL, X_OFFSET         INTEGER, X_SIZE           INTEGER, Y_OFFSET         INTEGER, Y_SIZE           INTEGER, PRIMARY KEY (RECORD_ID))";
        try (final Connection conn = GDDBData.getConnection()) {
            final boolean auto = conn.getAutoCommit();
            conn.setAutoCommit(false);
            try (final Statement st = conn.createStatement()) {
                if (GDDBUtil.tableExists(conn, "GDC_INVENTORY_GRID")) {
                    st.execute(dropTable);
                }
                st.execute(createTable);
                st.close();
                conn.commit();
            }
            catch (SQLException ex) {
                conn.rollback();
                final Object[] args = { "GDC_INVENTORY_GRID" };
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_CREATE_TABLE", args);
                GDMsgLogger.addError(msg);
                throw ex;
            }
            finally {
                conn.setAutoCommit(auto);
            }
        }
    }
    
    public static void insert(final ARZRecord record) throws SQLException {
        final DBInventoryGrid entry = get(record.getFileName());
        if (entry != null) {
            return;
        }
        final DBInventoryGrid grid = new DBInventoryGrid(record);
        final String insertBitmap = "INSERT INTO GDC_INVENTORY_GRID VALUES (?,?,?,?,?)";
        try (final Connection conn = GDDBData.getConnection()) {
            final boolean auto = conn.getAutoCommit();
            conn.setAutoCommit(false);
            try (final PreparedStatement ps = conn.prepareStatement(insertBitmap)) {
                ps.setString(1, grid.recordID);
                ps.setInt(2, grid.xOffset);
                ps.setInt(3, grid.xSize);
                ps.setInt(4, grid.yOffset);
                ps.setInt(5, grid.ySize);
                ps.executeUpdate();
                ps.close();
                conn.commit();
            }
            catch (SQLException ex) {
                conn.rollback();
                final Object[] args = { record.getFileName(), "GDC_INVENTORY_GRID" };
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_INS_TABLE_BY_ID", args);
                GDMsgLogger.addLowError(msg);
                GDMsgLogger.addLowError(ex);
            }
            finally {
                conn.setAutoCommit(auto);
            }
        }
        catch (SQLException ex2) {
            throw ex2;
        }
    }
    
    public static DBInventoryGrid get(final String recordID) {
        DBInventoryGrid grid = null;
        grid = DBInventoryGrid.hashBuffer.get(recordID);
        if (grid == null) {
            grid = getDB(recordID);
        }
        return grid;
    }
    
    private static DBInventoryGrid getDB(final String recordID) {
        DBInventoryGrid grid = null;
        final String command = "SELECT * FROM GDC_INVENTORY_GRID WHERE RECORD_ID = ?";
        try (final Connection conn = GDDBData.getConnection();
             final PreparedStatement ps = conn.prepareStatement(command)) {
            ps.setString(1, recordID);
            try (final ResultSet rs = ps.executeQuery()) {
                final List<DBInventoryGrid> list = wrap(rs);
                if (list.isEmpty()) {
                    grid = null;
                }
                else {
                    grid = list.get(0);
                }
                conn.commit();
            }
            catch (SQLException ex) {
                throw ex;
            }
        }
        catch (SQLException ex2) {
            final Object[] args = { recordID, "GDC_INVENTORY_GRID" };
            final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_READ_TABLE_BY_ID", args);
            GDMsgLogger.addError(msg);
            GDMsgLogger.addError(ex2);
        }
        return grid;
    }
    
    private static List<DBInventoryGrid> wrap(final ResultSet rs) throws SQLException {
        final LinkedList<DBInventoryGrid> list = new LinkedList<DBInventoryGrid>();
        final Blob blob = null;
        while (rs.next()) {
            final DBInventoryGrid grid = new DBInventoryGrid();
            grid.recordID = rs.getString(1);
            final DBInventoryGrid buff = DBInventoryGrid.hashBuffer.get(grid.recordID);
            if (buff != null) {
                list.add(buff);
            }
            else {
                grid.xOffset = rs.getInt(2);
                grid.xSize = rs.getInt(3);
                grid.yOffset = rs.getInt(4);
                grid.ySize = rs.getInt(5);
                list.add(grid);
                DBInventoryGrid.hashBuffer.put(grid.recordID, grid);
            }
        }
        return list;
    }
    
    static {
        DBInventoryGrid.hashBuffer = new ConcurrentHashMap<String, DBInventoryGrid>();
    }
}
